package com.smx.steppingstone.util;
import java.io.File;
import java.io.InputStream;
import java.util.Stack;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.*;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.InputSource;

/**
 * Utility to help us work with XML strings  and objects
 * @author gbugaj
 *
 */
public class XMLUtil {

	/**
	 * Converts the specified string which is in ASCII format to
	 * legal XML format.
	 * Inspired by XMLWriter by http://www.megginson.com/Software/
	 */
	public static String convertAsciiToXml(String string) {
		if(string == null || string.equals("")) return "";

		StringBuffer sbuf=new StringBuffer();
		char ch[]=string.toCharArray();
		for(int i=0;i<ch.length;i++){
			switch (ch[i]) {
			case '&':
				sbuf.append("&amp;");
				break;
			case '<':
				sbuf.append("&lt;");
				break;
			case '>':
				sbuf.append("&gt;");
				break;
			case '\"':
				sbuf.append('\"');
				break;
			default:
				if (ch[i] > '\u007f') {
					sbuf.append("&#");
					sbuf.append(Integer.toString(ch[i]));
					sbuf.append(';');
				}  else if (ch[i]=='\t'){
					sbuf.append(' ');
					sbuf.append(' ');
					sbuf.append(' ');
					sbuf.append(' ');
				}
				else if( (int)ch[i]>=32   || (ch[i]=='\n' || ch[i]=='\r')) {
					sbuf.append(ch[i]);
				}
			}
		}        
		return sbuf.toString();
	}
	/**
	 * Returns newly constucted document builder
	 * @return
	 * @throws Exception
	 */
	private static DocumentBuilder getDocumentBuilder() throws Exception{
		String  JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
		String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
		String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
		DocumentBuilderFactory docBuildFactory = DocumentBuilderFactory.newInstance();
		docBuildFactory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); // use
		// LANGUAGE
		// SOURCE
		docBuildFactory.setValidating(false);
		docBuildFactory.setNamespaceAware(false);
		DocumentBuilder documentBuilder = docBuildFactory.newDocumentBuilder();

		/**
		 * TODO: Incorporate Log4J to keep track of errors
		 * Custom ErrorHandler for the XML Document
		 */
		documentBuilder.setErrorHandler(new ErrorHandler(){

			public void error(SAXParseException arg0) throws SAXException {
				System.out.println(arg0);
			}

			public void fatalError(SAXParseException arg0) throws SAXException {
				System.out.println(arg0);
			}

			public void warning(SAXParseException arg0) throws SAXException {
				System.out.println(arg0);
			}});

		return documentBuilder;
	}


	public static Document getXmlDocument(String _xmlFilePath)throws Exception {
		return getDocumentBuilder().parse(new File(_xmlFilePath));
	}

	public static Document getXmlDocument(InputSource inputSource) throws Exception{
		return getDocumentBuilder().parse(inputSource);
	}

	public static Document getXmlDocument(InputStream stream) throws Exception{
		return getDocumentBuilder().parse(new InputSource(stream));
	}


	public static void c(Object o){
		System.out.println(o);
	}

	/**
	 * Find maximum depth for given node type
	 * @param node
	 * @param nodeName
	 * @return
	 */
	public static int maxDepth(Object node,String nodeName){
		int maxCount=1;
		try {
			NodeList list=extract("//"+nodeName, node);			
			for(int i=0;i<list.getLength();i++){
				Node item=list.item(i);
				Node tmp=item.getParentNode();
				int counter=1;
				while(tmp!=null){
					if(tmp.getNodeName().equals(nodeName)){
						counter++;
					}
					tmp=tmp.getParentNode();
				}
				if(counter>maxCount){
					maxCount=counter;
				}
			}
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}
		return maxCount;
	}

	/**
	 * Extract Data using  xpath from given object
	 *
	 * @param sXpath
	 * @param node
	 * @return
	 * @throws javax.xml.xpath.XPathExpressionException
	 */
	public static NodeList extract(String sXpath, Object node) throws XPathExpressionException {
		XPathFactory factory = XPathFactory.newInstance();
		XPath xpath = factory.newXPath();
		XPathExpression exprFilter = xpath.compile(sXpath);
		NodeList nodesFilter = (NodeList) exprFilter.evaluate(node, XPathConstants.NODESET);
		return nodesFilter;
	}


}
